#include <malloc.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/time.h>
#include <time.h>
#include <math.h>
#ifdef DAG
#include "aceMesh_runtime_c.h"
#endif

long N;
long CHUNK_SIZE;

void initialize(long length, long chunk_size, double *data_A, double *data_B);
double dot_product(long N, long CHUNK_SIZE, double *A, double *B);
void initialize_dag(long length, long chunk_size, double *data_A, double *data_B);
double dot_product_dag(long N, long CHUNK_SIZE, double *A, double *B);
double dot_product_dag_reduction(long N, long CHUNK_SIZE, double *A, double *B, int length);

int main(int argc, char *argv[]) {
    struct timeval start;
    struct timeval stop;
    unsigned long elapsed;
    double result,test_result;

    if (argc != 3) {
        fprintf(stderr, "Usage: %s <vector size in K> <chunk size in K>\n", argv[0]);
        return 1;
    }

    N = atol(argv[1])*1024L;
    CHUNK_SIZE = atol(argv[2])*1024L;

    double *A = (double*)malloc(N*sizeof(double));
    double *B = (double*)malloc(N*sizeof(double));

    double *testA = (double*)malloc(N*sizeof(double));
    double *testB = (double*)malloc(N*sizeof(double));


    if (A == NULL || B == NULL)
    {
        printf("Error: Can't allocate %ld Bytes\nExiting.\n", N*sizeof(double));
        exit(1);
    }

#ifdef DAG
    acemesh_runtime_init(64);
#endif
    gettimeofday(&start, NULL);

#ifdef DAG
    initialize_dag(N, CHUNK_SIZE, A, B);
#else
    initialize(N, CHUNK_SIZE, A, B);
#endif

#ifdef DAG
  #ifdef REDUCTION
    result = dot_product_dag_reduction(N, CHUNK_SIZE, A, B, ceil(N/CHUNK_SIZE));
  #else
    result = dot_product_dag(N, CHUNK_SIZE, A, B);
  #endif
#else
    result = dot_product(N, CHUNK_SIZE, A, B);
#endif

    gettimeofday(&stop, NULL);

#ifdef DAG
    acemesh_runtime_shutdown();  
#endif

    initialize(N, CHUNK_SIZE, testA, testB);

    test_result = dot_product(N, CHUNK_SIZE, testA, testB);

    elapsed = 1000000*(stop.tv_sec - start.tv_sec);
    elapsed += stop.tv_usec - start.tv_usec;

    printf("size (K), %lu, chunk (K), %lu, time (ms), %lu\n", N/1024, CHUNK_SIZE/1024, elapsed/1000);
    if(test_result-result > 1e-16)
    {
        printf("check error\n");
//        printf("%lf\t%lf\t%lf\n",test_result,result,test_result-result);
    }
    else
       printf("check OK\n");
}
